home *** CD-ROM | disk | FTP | other *** search
- #include "idbsp.h"
-
- /*
- I assume that a grid 8 is used for the maps, so a point will be considered
- on a line if it is within 8 pixels of it. The accounts for floating error.
- */
-
- int cuts; /* number of new lines generated by BSP process */
-
- /*
- ==================
- =
- = DivlineFromWorldline
- =
- ==================
- */
-
- void DivlineFromWorldline(divline_t * d, line_t * w)
- {
- d -> pt = w -> p1;
- d -> dx = w -> p2.x - w -> p1.x;
- d -> dy = w -> p2.y - w -> p1.y;
- }
-
- /*
- ==================
- =
- = PointOnSide
- =
- = Returns side 0 (front), 1 (back), or -1 (colinear)
- ==================
- */
-
- /*
- #define POS_RADIUS 2.0 // original
-
- sometimes a radius of 1.5 has produced better results.
- */
-
- #define POS_RADIUS 2.0
- #define NEWPOS
-
- int PointOnSideTol(NXPoint * p, divline_t * l, double Tol)
- {
- int retval;
-
- #ifdef NEWPOS
- float y;
- #else
- float dx,
- dy;
- float left,
- right;
- float a,
- b,
- c,
- d;
-
- #endif
-
-
-
- #ifdef NEWPOS
- y = ((p -> y - l -> pt.y) * l -> dx - (p -> x - l -> pt.x) * l -> dy) /
- sqrt(l -> dx * l -> dx + l -> dy * l -> dy);
-
- if (fabs(y) < Tol)
- retval = -1;
- else
- retval = (y < 0.0) ? 0 : 1;
- #else
- if (!l -> dx)
- {
- if (p -> x > (l -> pt.x - Tol) && p -> x < (l -> pt.x + Tol))
- retval = -1;
- else
- {
- if (p -> x < l -> pt.x)
- retval = l -> dy > 0;
- else
- retval = l -> dy < 0;
- }
- }
- else if (!l -> dy)
- {
- if (p -> y > (l -> pt.y - Tol) && p -> y < (l -> pt.y + Tol))
- retval = -1;
- else
- {
- if (p -> y < l -> pt.y)
- retval = l -> dx < 0;
- else
- retval = l -> dx > 0;
- }
- }
- else
- {
-
- dx = l -> pt.x - p -> x;
- dy = l -> pt.y - p -> y;
- a = l -> dx * l -> dx + l -> dy * l -> dy;
- b = 2 * (l -> dx * dx + l -> dy * dy);
- c = dx * dx + dy * dy - (POS_RADIUS * POS_RADIUS);
- d = b * b - 4 * a * c;
-
- if (d > 0)
- retval = -1;
- else
- {
- dx = p -> x - l -> pt.x;
- dy = p -> y - l -> pt.y;
-
- left = l -> dy * dx;
- right = dy * l -> dx;
-
- if (fabs(left - right) < 0.5)
- retval = -1; /* on line */
- else
- {
- if (right < left)
- retval = 0; /* front side */
- else
- retval = 1; /* back side */
- }
- }
- }
- #endif
-
- /*if (myval != retval)
- {
- printf("\nPOS: line (% 5g, % 5g) - % 5g, % 5g: pt (% 5g, % 5g): me % d: JC % d:\n",
- l->pt.x, l->pt.y, l->dx, l->dy, p->x, p->y, myval, retval);
- } */
- /*return myval; */
- return retval;
- }
-
- int PointOnSide(NXPoint * p, divline_t * l)
- {
- return PointOnSideTol(p, l, POS_RADIUS);
- }
-
- /*
- =============
- =
- = sign
- =
- = Returns -1, 0, or 1, based on the input sign
- =
- ==============
- */
-
- int sign(float i)
- {
- if (i < 0)
- return -1;
- else if (i > 0)
- return 1;
- return 0;
- }
-
- /*
- ==================
- =
- = LineOnSide
- =
- = Returns side 0 / 1, or -2 if line must be split
- = If the line is colinear, it will be placed on the front side if
- = it is going the same direction as the dividing line
- ==================
- */
-
- #define NEWLOS
-
- boolean LineOnSide(line_t * wl, divline_t * bl)
- {
- int s1,
- s2;
- float dx,
- dy;
-
- s1 = PointOnSide(&wl -> p1, bl);
- s2 = PointOnSide(&wl -> p2, bl);
-
- if (s1 == s2)
- {
- if (s1 == -1)
- { /* colinear, so see if the directions are the same */
- dx = wl -> p2.x - wl -> p1.x;
- dy = wl -> p2.y - wl -> p1.y;
-
- #ifdef NEWLOS
- if (((bl -> dx * dx + bl -> dy * dy) / sqrt(dx * dx + dy * dy)) > 0.0)
- #else
- if (sign(dx) == sign(bl -> dx) && sign(dy) == sign(bl -> dy))
- #endif
-
- return 0;
- return 1;
- }
- return s1;
- }
- if (s1 == -1)
- return s2;
- if (s2 == -1)
- return s1;
-
- return -2;
- }
-
- /*
- ===============
- =
- = InterceptVector
- =
- = Returns the fractional intercept point along first vector
- ===============
- */
-
- double InterceptVector(divline_t * v2, divline_t * v1)
- {
-
- #if 0
- v1.x + f1 * v1.xs = v2.x + f2 * v2.xs(parametric x coordinates)
- f1 *v1.xs = v2.x - v1.x + f2 * v2.xs
- f1 = (v2.x - v1.x + f2 * v2.xs) / v1.xs
-
- v1.y + f1 * v1.ys = v2.y + f2 * v2.ys(parametric y coordinates)
- f1 = (v2.y - v1.y + f2 * v2.ys) / v1.ys
-
- f1 = (v2.x - v1.x + f2 * v2.xs) / v1.xs = (v2.y - v1.y + f2 * v2.ys) / v1.ys
- v1.ys * v2.x - v1.ys * v1.x + v1.ys * v2.xs * f2 = v1.xs * v2.y - v1.xs * v1.y + v1.xs * v2.ys * f2
- (v1.ys * v2.xs - v1.xs * v2.ys) * f2 = -v1.ys * v2.x + v1.ys * v1.x + v1.xs * v2.y - v1.xs * v1.y
- = v1.ys * (v1.x - v2.x) + v1.xs * (v2.y - v1.y)
-
- f2 = (v1.ys * (v1.x - v2.x) + v1.xs * (v2.y - v1.y)) / (v1.ys * v2.xs - v1.xs * v2.ys)
- #endif
-
-
- float frac,
- num,
- den;
-
-
- den = v1 -> dy * v2 -> dx - v1 -> dx * v2 -> dy;
- if (den == 0)
- Error("InterceptVector: parallel");
- num = (v1 -> pt.x - v2 -> pt.x) * v1 -> dy + (v2 -> pt.y - v1 -> pt.y) * v1 -> dx;
- frac = num / den;
-
- if (frac <= 0.0 || frac >= 1.0)
- Error("InterceptVector: intersection outside line");
-
- return frac;
- }
-
-
- /*
- ==================
- =
- = CutLine
- =
- = Truncates the given worldline to the front side of the divline
- = and returns the cut off back side in a newly allocated worldline
- ==================
- */
-
- double round(float x)
- {
- if (x > 0)
- {
- if (x - (int)x < 0.1)
- return (int)x;
- else if (x - (int)x > 0.9)
- return (int)x + 1;
- else
- return x;
- }
-
- if ((int)x - x < 0.1)
- return (int)x;
- else if ((int)x - x > 0.9)
- return (int)x - 1;
- return x;
- }
-
- line_t *CutLine(line_t * wl, divline_t * bl)
- {
- int side;
- line_t *new_p;
- divline_t wld;
- float frac;
- NXPoint intr;
- int offset;
- double ndx,
- ndy;
-
- cuts++;
- DivlineFromWorldline(&wld, wl);
- new_p = (line_t *) malloc(sizeof(line_t));
- memset(new_p, 0, sizeof(*new_p));
- *new_p = *wl;
-
- frac = InterceptVector(&wld, bl);
- ndx = floor((wld.dx * frac) + 0.5);
- ndy = floor((wld.dy * frac) + 0.5);
- intr.x = wld.pt.x + (int)ndx;
- intr.y = wld.pt.y + (int)ndy;
- offset = wl -> offset + (int)floor(sqrt(ndx * ndx + ndy * ndy) + 0.5);
- side = PointOnSide(&wl -> p1, bl);
- if (side == 0)
- { /* line starts on front side */
- wl -> p2 = intr;
- new_p -> p1 = intr;
- new_p -> offset = offset;
- }
- else
- { /* line starts on back side */
- wl -> p1 = intr;
- wl -> offset = offset;
- new_p -> p2 = intr;
- }
-
- return new_p;
- }
-
-
- /*
- ================
- =
- = EvaluateSplit
- =
- = Returns a number grading the quality of a split along the givent line
- = for the current list of lines. Evaluation is halted as soon as it is
- = determined that a better split already exists
- =
- = A split is good if it divides the lines evenly without cutting many lines
- = A horizontal or vertical split is better than a sloping split
- =
- = The LOWER the returned value, the better. If the split line does not divide
- = any of the lines at all, MAXINT will be returned
- ================
- */
-
- /*int EvaluateSplit (id lines_i, line_t *spliton, int bestgrade)
- */
- int EvaluateSplit(STORAGE * lines_i, line_t * spliton, int bestgrade)
- {
- int i,
- c,
- side;
- line_t *line_p;
- divline_t divline;
- int frontcount,
- backcount,
- max,
- new;
- int grade;
- worldline_t *wl;
-
- /* wl = [linestore_i elementAt: spliton->linedef];
- */
- wl = (worldline_t *) linestore_i -> data + spliton -> linedef;
-
- #if 0
- if (wl -> special == BSPSLIDEENDSPECIAL)
- return MAXINT; /* NEVER split on this, because it moves */
- #endif
-
- DivlineFromWorldline(&divline, spliton);
-
- frontcount = backcount = 0;
- /* c = [lines_i count];
- */
- c = lines_i -> count;
- grade = 0;
-
- for (i = 0; i < c; i++)
- {
- /* line_p = [lines_i elementAt:i];
- */
- line_p = (line_t *) lines_i -> data + i;
- if (line_p == spliton)
- side = 0;
- else
- side = LineOnSide(line_p, &divline);
- switch (side)
- {
- case 0:
- frontcount++;
- break;
- case 1:
- backcount++;
- break;
- case -2:
- /* wl = [linestore_i elementAt: line_p->linedef];
- */
- wl = (worldline_t *) linestore_i -> data + line_p -> linedef;
-
- #if 0
- if (wl -> special == BSPSLIDESIDESPECIAL)
- return MAXINT; /* NEVER split this line, because it slides */
- #endif
-
- frontcount++;
- backcount++;
- break;
- }
-
- max = MAX(frontcount, backcount);
- new = (frontcount + backcount) - c;
- grade = max + new * 8;
- if (grade > bestgrade)
- return grade; /* might as well stop now */
- }
-
- if (frontcount == 0 || backcount == 0)
- return INT_MAX; /* line does not partition at all */
-
- return grade;
- }
-
-
- /*
- ================
- =
- = ExecuteSplit
- =
- = Actually splits the line list as EvaluateLines predicted
- ================
- */
- /*
- void ExecuteSplit (id lines_i, line_t *spliton
- , id frontlist_i, id backlist_i)
- */
- void ExecuteSplit(STORAGE * lines_i, line_t * spliton,
- STORAGE * frontlist_i, STORAGE * backlist_i)
- {
- int i,
- c,
- side;
- line_t *line_p,
- *newline_p;
- divline_t divline;
-
- DivlineFromWorldline(&divline, spliton);
- DrawDivLine(&divline);
-
- /* c = [lines_i count];
- */
- c = lines_i -> count;
-
- for (i = 0; i < c; i++)
- {
- /* line_p = [lines_i elementAt:i];
- */
- line_p = (line_t *) lines_i -> data + i;
- if (line_p == spliton)
- side = 0;
- else
- side = LineOnSide(line_p, &divline);
- switch (side)
- {
- case 0:
- /* [frontlist_i addElement: line_p];
- */
- memcpy((line_t *) frontlist_i -> data + frontlist_i -> count, line_p, sizeof(line_t));
- frontlist_i -> count += 1;
- frontlist_i -> data = (line_t *) realloc(frontlist_i -> data,
- sizeof(line_t) * (frontlist_i -> count + 1));
- break;
- case 1:
- /* [backlist_i addElement: line_p];
- */
- memcpy((line_t *) backlist_i -> data + backlist_i -> count, line_p, sizeof(line_t));
- backlist_i -> count += 1;
- backlist_i -> data = (line_t *) realloc(backlist_i -> data,
- sizeof(line_t) * (backlist_i -> count + 1));
- break;
- case -2:
- newline_p = CutLine(line_p, &divline);
- /* [frontlist_i addElement: line_p];
- [backlist_i addElement: newline_p];
- */
- memcpy((line_t *) frontlist_i -> data + frontlist_i -> count, line_p, sizeof(line_t));
- frontlist_i -> count += 1;
- frontlist_i -> data = (line_t *) realloc(frontlist_i -> data,
- sizeof(line_t) * (frontlist_i -> count + 1));
-
- memcpy((line_t *) backlist_i -> data + backlist_i -> count, newline_p, sizeof(line_t));
- backlist_i -> count += 1;
- backlist_i -> data = (line_t *) realloc(backlist_i -> data,
- sizeof(line_t) * (backlist_i -> count + 1));
-
- break;
- default:
- Error("ExecuteSplit: bad side");
- }
- }
- }
-
-
- /*
- ================
- =
- = BSPList
- =
- = Takes a storage of lines and recursively partitions the list
- = Returns a bspnode_t
- ================
- */
-
- /* float gray = NX_WHITE; */
- float gray = 0;
-
- /* bspnode_t *BSPList (id lines_i)
- */
- bspnode_t *BSPList(STORAGE * lines_i)
- {
- /* id frontlist_i, backlist_i;
- */
- STORAGE *frontlist_i,
- *backlist_i;
- int i,
- c,
- step;
- line_t *line_p,
- *bestline_p;
- int v,
- bestv;
- bspnode_t *node_p;
-
- /*
- if (draw)
- PSsetgray (gray);
- gray = 1.0 - gray;
- */
- DrawLineStore(lines_i);
-
- node_p = (bspnode_t *) malloc(sizeof(*node_p));
- memset(node_p, 0, sizeof(*node_p));
-
- /*
- find the best line to partition on
- */
-
- /* c = [lines_i count];
- */
-
- c = lines_i -> count;
- bestv = INT_MAX;
- bestline_p = NULL;
- step = (c / 40) + 1; /* set this to 1 for an exhaustive search */
- research:
- for (i = 0; i < c; i += step)
- {
- /* line_p = [lines_i elementAt:i];
- */
- line_p = (line_t *) lines_i -> data + i;
- v = EvaluateSplit(lines_i, line_p, bestv);
- if (v < bestv)
- {
- bestv = v;
- bestline_p = line_p;
- }
- }
-
- /*
- if none of the lines should be split, the remaining lines
- are convex, and form a terminal node
- */
- /*
- printf ("bestv:%i\n",bestv);
- */
- if (bestv == INT_MAX)
- {
- if (step > 1)
- { /* possible to get here with non convex area if BSPSLIDE specials
- caused rejections */
- step = 1;
- goto research;
- }
- node_p -> lines_i = lines_i;
- return node_p;
- }
-
- /*
- divide the line list into two nodes along the best split line
- */
- DivlineFromWorldline(&node_p -> divline, bestline_p);
- /*
- frontlist_i =
- [[Storage alloc]
- initCount: 0
- elementSize: sizeof(line_t)
- description: NULL];
- backlist_i =
- [[Storage alloc]
- initCount: 0
- elementSize: sizeof(line_t)
- description: NULL];
- */
- frontlist_i = (STORAGE *) SafeMalloc(sizeof(STORAGE));
- frontlist_i -> count = 0;
- frontlist_i -> size = sizeof(line_t);
- frontlist_i -> data = (line_t *) SafeMalloc(sizeof(line_t));
-
- backlist_i = (STORAGE *) SafeMalloc(sizeof(STORAGE));
- backlist_i -> count = 0;
- backlist_i -> size = sizeof(line_t);
- backlist_i -> data = (line_t *) SafeMalloc(sizeof(line_t));
-
- ExecuteSplit(lines_i, bestline_p, frontlist_i, backlist_i);
-
- /*
- recursively divide the lists
- */
- node_p -> side[0] = BSPList(frontlist_i);
- node_p -> side[1] = BSPList(backlist_i);
-
- return node_p;
- }
-
-
-
- /*
- =====================
- =
- = MakeSegs
- =
- =====================
- */
-
- /* id segstore_i;
- */
- STORAGE *segstore_i;
-
- void MakeSegs(void)
- {
- int i,
- count;
- worldline_t *wl;
-
- /* line_t li;
- */
- line_t *li;
-
- /*
- segstore_i =
- [[Storage alloc]
- initCount: 0
- elementSize: sizeof(line_t)
- description: NULL];
- */
- segstore_i = (STORAGE *) SafeMalloc(sizeof(STORAGE));
- segstore_i -> data = (line_t *) SafeMalloc(sizeof(line_t));
- segstore_i -> count = 0;
- segstore_i -> size = sizeof(line_t);
-
- /*
- count = [linestore_i count];
- wl = [linestore_i elementAt:0];
- */
- count = linestore_i -> count;
- wl = linestore_i -> data;
-
- li = segstore_i -> data;
-
- for (i = 0; i < count; i++, wl++)
- {
- li -> p1 = wl -> p1;
- li -> p2 = wl -> p2;
- li -> linedef = i;
- li -> side = 0;
- li -> offset = 0;
- li -> grouped = false;
-
- /* [segstore_i addElement: &li];
- */
- segstore_i -> count += 1;
- segstore_i -> data = (line_t *) realloc(segstore_i -> data,
- sizeof(line_t) * (segstore_i -> count + 1));
- li = (line_t *) segstore_i -> data + segstore_i -> count;
-
- if (wl -> flags & ML_TWOSIDED)
- {
- li -> p1 = wl -> p2;
- li -> p2 = wl -> p1;
- li -> linedef = i;
- li -> side = 1;
- li -> offset = 0;
- li -> grouped = false;
- /* [segstore_i addElement: &li];
- */
- segstore_i -> count += 1;
- segstore_i -> data = (line_t *) realloc(segstore_i -> data,
- sizeof(line_t) * (segstore_i -> count + 1));
- li = (line_t *) segstore_i -> data + segstore_i -> count;
- }
- }
- }
-
-
- /*
- =====================
- =
- = BuildBSP
- =
- =====================
- */
-
- bspnode_t *startnode;
-
- void BuildBSP(void)
- {
- MakeSegs();
- cuts = 0;
- startnode = BSPList(segstore_i);
- }
-